#pragma once

#include <string>
#include <jsoncpp/json/json.h>
#include <iostream>
#include <memory>
#include <iostream>

static const std::string sep = "\r\n";

std::string Encode(std::string &jsonstr)
{
    // if(jsonstr.empty()) return "";
    int len = jsonstr.size();
    return std::to_string(len) + sep + jsonstr + sep;
}

std::string Decode(std::string &packagestream)
{
    auto pos = packagestream.find(sep);
    if(pos == std::string::npos)
        return std::string();
    std::string lenstr= packagestream.substr(0, pos);
    int jsonlen = std::stoi(lenstr);
    int total = jsonlen + lenstr.size() + sep.size() * 2;
    if(packagestream.size() < total)
        return std::string();
    std::string json = packagestream.substr(pos+sep.size(), jsonlen);
    packagestream.erase(0, total);
    return json;
}

class Request
{
public:
    Request(int x, int y, char oper)
        : _x(x), _y(y), _oper(oper)
    {
    }
    Request()
    {
    }
    ~Request()
    {
    }

    bool Serialize(std::string *out)
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;

        Json::FastWriter write;
        *out = write.write(root);
        return true;
    }

    bool DeSerialize(const std::string &in)
    {
        Json::Value root;
        Json::Reader reader;
        reader.parse(in, root);

        _x = root["x"].asInt();
        _y = root["y"].asInt();
        _oper = root["oper"].asInt();

        return true;
    }

    void SetValue(int x, int y, char oper)
    {
        _x = x;
        _y = y;
        _oper = oper;
    }

    void Print()
    {
        printf("%d %c %d\n", _x, _oper, _y);
    }


    int X() { return _x; }
    int Y() { return _y; }
    char Oper() { return _oper; }

private:
    int _x;
    int _y;
    char _oper;
};

class Response
{
public:
    Response()
    {
    }
    ~Response()
    {
    }

    bool Serialize(std::string *out)
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;
        root["desc"] = _desc;

        Json::FastWriter write;
        *out = write.write(root);
        return true;
    }

    bool DeSerialize(const std::string &in)
    {
        Json::Value root;
        Json::Reader reader;
        reader.parse(in, root);

        _result = root["result"].asInt();
        _code = root["code"].asInt();
        _desc = root["desc"].asCString();

        return true;
    }
    void PrintSult()
    {
        printf("Result: %d, Code: %d, Desc: %s\n", _result, _code, _desc.c_str());
    }

    int _result;
    int _code;
    std::string _desc;
};

class Factory
{
public:
    static std::shared_ptr<Request> BuildRequestDefault()
    {
        return std::make_shared<Request>();
    }
    static std::shared_ptr<Response> BuildResponseDefault()
    {
        return std::make_shared<Response>();
    }
    
};

